package edu.software.PBL_Management_System.service.impl;

import edu.software.PBL_Management_System.dto.ChatRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.software.PBL_Management_System.service.DifyService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * Dify API 服务实现类
 * 负责与Dify智能体API进行通信，支持普通模式和流式模式
 */
@Service
public class DifyServiceImpl implements DifyService {

    /**
     * Dify API 基础URL，从配置文件读取
     */
    @Value("${dify.api.base-url}")
    private String difyBaseUrl;

    /**
     * Dify API 密钥，从配置文件读取
     * 必须在application.properties或application.yml中配置
     */
    @Value("${dify.api.complete.key}")
    private String difyApiKey;

    /**
     * WebClient 实例，用于发送HTTP请求
     */
    private final WebClient webClient;

    /**
     * JSON序列化/反序列化工具
     */
    private final ObjectMapper objectMapper;

    /**
     * 构造函数 - 初始化WebClient和ObjectMapper
     */
    public DifyServiceImpl() {
        // 创建WebClient实例，配置超时时间
        this.webClient = WebClient.builder()
                .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(1024 * 1024)) // 设置最大内存缓冲区1MB
                .build();
        this.objectMapper = new ObjectMapper();
    }

    /**
     * 发送消息到Dify（阻塞模式）
     * 等待完整响应后返回结果
     *
     * @param request 聊天请求对象
     * @return String Dify返回的完整响应
     * @throws RuntimeException 当API调用失败时抛出异常
     */
    @Override
    public String sendMessage(ChatRequest request) {
        try {
            System.out.println("=== 开始调用Dify API（阻塞模式） ===");

            // 准备发送给Dify的请求数据
            Map<String, Object> difyRequest = prepareDifyRequest(request);
            System.out.println("发送到Dify的请求数据: " + objectMapper.writeValueAsString(difyRequest));

            // 发送POST请求到Dify API
            String response = webClient.post()
                    .uri(difyBaseUrl + "/chat-messages")  // Dify聊天消息API端点
                    .header("Authorization", "Bearer " + difyApiKey)  // 设置认证头
                    .header("Content-Type", "application/json")       // 设置内容类型
                    .bodyValue(difyRequest)  // 设置请求体
                    .retrieve()  // 开始请求
                    .bodyToMono(String.class)  // 转换响应为String
                    .timeout(Duration.ofSeconds(60))  // 设置60秒超时
                    .block();  // 阻塞等待响应

            // 输出Dify返回的响应到控制台（后续可存储到数据库）
            System.out.println("=== Dify API 响应 ===");
            System.out.println(response);
            System.out.println("=== 响应结束 ===");

            return response;

        } catch (Exception e) {
            System.err.println("调用Dify API时发生错误: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("Dify API调用失败", e);
        }
    }

    /**
     * 发送消息到Dify（流式模式）
     * 实时接收并转发Dify的流式响应
     *
     * @param request 聊天请求对象
     * @return Flux<String> 流式响应数据流
     */
    @Override
    public Flux<String> sendMessageStream(ChatRequest request) {
        try {
            System.out.println("=== 开始调用Dify API（流式模式） ===");

            // 准备发送给Dify的请求数据（强制设置为流式模式）
            Map<String, Object> difyRequest = prepareDifyRequest(request);
            difyRequest.put("response_mode", "streaming");  // 强制设置为流式模式

            System.out.println("发送到Dify的流式请求数据: " + objectMapper.writeValueAsString(difyRequest));

            return webClient.post()
                    .uri(difyBaseUrl + "/chat-messages")  // Dify聊天消息API端点
                    .header("Authorization", "Bearer " + difyApiKey)  // 设置认证头
                    .header("Content-Type", "application/json")       // 设置内容类型
                    .header("Accept", "text/event-stream")            // 接受SSE流
                    .bodyValue(difyRequest)  // 设置请求体
                    .retrieve()  // 开始请求
                    .bodyToFlux(String.class)  // 转换为流式响应
                    .timeout(Duration.ofSeconds(120))  // 设置120秒超时（流式响应可能较长）
                    // 处理每个接收到的数据块
                    .doOnNext(data -> {
                        System.out.println("=== 收到Dify流式数据 ===");
                        System.out.println(data);
                        System.out.println("=== 数据块结束 ===");
                        // 这里可以添加数据库存储逻辑
                        // saveStreamDataToDatabase(data);
                    })
                    // 流完成时的处理
                    .doOnComplete(() -> System.out.println("=== Dify流式响应完成 ==="))
                    // 错误处理
                    .doOnError(error -> {
                        System.err.println("Dify流式响应错误: " + error.getMessage());
                        error.printStackTrace();
                    })
                    // 当发生错误时返回错误信息
                    .onErrorReturn("流式响应发生错误，请重试");

        } catch (Exception e) {
            System.err.println("初始化Dify流式API调用时发生错误: " + e.getMessage());
            e.printStackTrace();
            // 返回包含错误信息的单元素流
            return Flux.just("流式服务初始化失败: " + e.getMessage());
        }
    }

    /**
     * 准备发送给Dify的请求数据
     * 将前端的ChatRequest转换为Dify API所需的格式
     *
     * @param request 前端聊天请求
     * @return Map<String, Object> Dify API请求格式
     */
    private Map<String, Object> prepareDifyRequest(ChatRequest request) {
        System.out.println("准备Dify请求数据...");

        Map<String, Object> difyRequest = new HashMap<>();

        // 设置必要的请求参数
        difyRequest.put("query", request.getQuery());  // 用户查询内容
        difyRequest.put("inputs", request.getInputs() != null ? request.getInputs() : new HashMap<>());  // 输入参数
        difyRequest.put("response_mode", request.getResponseMode());  // 响应模式
        difyRequest.put("user", request.getUser());  // 用户标识
        difyRequest.put("conversation_id", request.getConversationId());  // 会话ID

        // 如果有文件附件，添加到请求中
        if (request.getFiles() != null && !request.getFiles().isEmpty()) {
            difyRequest.put("files", request.getFiles());
            System.out.println("包含 " + request.getFiles().size() + " 个文件附件");
        }

        // 设置是否自动生成会话名称
        difyRequest.put("auto_generate_name", request.getAutoGenerateName());

        System.out.println("Dify请求数据准备完成");
        return difyRequest;
    }


}